package top.went.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.went.db.dao.*;
import top.went.db.mapper.OutStorageMapper;
import top.went.db.mapper.WpDetailWapper;
import top.went.exception.NotFoundException;
import top.went.exception.ServiceException;
import top.went.pojo.*;
import top.went.utils.WarehouseUtils;
import top.went.vo.*;

import java.math.BigDecimal;
import java.sql.Date;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 出入库
 */
@Service
@Transactional(value = "transactionManager",rollbackFor = ServiceException.class)
public class WareHouseOutIn {
    @Autowired
    private WpDetailWapper wpDetailWapper;
    @Autowired
    private WareHouseDetailDao detailDao;
    @Autowired
    private WareHouseService wareHouseService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private ProductService productService;
    @Autowired
    private WhPullDao whPullDao;
    @Autowired
    private InStorageDao inStorageDao;
    @Autowired
    private OutStorageMapper outStorageMapper;
    @Autowired
    private WarehouseSend warehouseSend;
    @Autowired
    private WareHouseDetailDao wareHouseDetailDao;
    @Autowired
    private PurchaseService purchaseService;
    @Autowired
    private ReturnGoodsService returnGoodsService;
    @Autowired
    private ReturnGoodsDao returnGoodsDao;


    /** 表格排序*/
    private static Map<String,String> map = new HashMap<>();
    static {
        map.put("dgDate","dg_Date");
        map.put("orderTitle","orderTitle");
        map.put("cusName","cusName");
        map.put("status","status");
        map.put("dgNumber","dg_number");
        map.put("ddDate","dd_Date");
        map.put("ddNumber","dd_Number");
    }

    /**
     * 加载出库明细
     * @param id
     * @return
     * @throws NotFoundException
     */
    public List<DetailOutVo> loadOutDetail(Long id) throws NotFoundException {
        wareHouseService.loadOut(id.intValue());
        return  wpDetailWapper.findDetail(id,0);
    }
    /**
     * 加载入库明细
     * @param id
     * @return
     * @throws NotFoundException
     */
    public List<DetailOutVo> loadInDetail(Long id) throws NotFoundException {
        wareHouseService.loadIn(id.intValue());
        return  wpDetailWapper.findDetail(id,1);
    }

    /**
     * 修改产品明细
     * @param warehouseDetailVo
     * @throws NotFoundException
     * @throws ServiceException
     */
    public void modifyDetail(WarehouseDetailVo warehouseDetailVo) throws NotFoundException, ServiceException {
        List<WpDetailEntity> wpDetailEntities= doModify(warehouseDetailVo);
        try {
            detailDao.delete(getDeleteDetail(loadAllDetail(warehouseDetailVo.getType()?1:0,warehouseDetailVo.getId().intValue()),
                    wpDetailEntities));
            detailDao.save(wpDetailEntities);
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("修改明细失败");
        }

    }
    private List<WpDetailEntity> doModify(WarehouseDetailVo warehouseDetailVo) throws NotFoundException, ServiceException {
        int id = warehouseDetailVo.getId().intValue();
        WarehouseEntity warehouseEntity;
        CustomerEntity customerEntity;
        if (!warehouseDetailVo.getType()) {
            WhPullEntity out = wareHouseService.loadOut(id);
            if (out.getWpullStatus() != 0)
                throw new ServiceException("已执行的出库单不允许编辑");
            warehouseEntity = out.getTbWarehouseByWhId();
            customerEntity = out.getTbOrderByOrderId()!=null?out.getTbOrderByOrderId().getTbCustomerByCusId():null;
        } else {
            WhPutEntity in = wareHouseService.loadIn(id);
            if (in.getWpStatus() != 0)
                throw new ServiceException("已执行的入库单不允许编辑");
            warehouseEntity = in.getTbWarehouseByWhId();
            customerEntity = in.getTbPurchaseByPurId() != null ? in.getTbPurchaseByPurId().getTbCustomerByCusId() : null;
        }
        return buildDetails(warehouseDetailVo, warehouseEntity,customerEntity);
    }

    /**
     * 获取要删除的明细
     * @param loadAllDetail
     * @param wpDetailEntities
     */
    private List<WpDetailEntity> getDeleteDetail(List<WpDetailEntity> loadAllDetail, List<WpDetailEntity> wpDetailEntities) {
        List<WpDetailEntity> deleteArray = new ArrayList<>();
        if (loadAllDetail != null) {
            boolean in ;
            for (WpDetailEntity wpDetailEntity : loadAllDetail) {
                in = false;
                for (WpDetailEntity detailEntity : wpDetailEntities) {
                    if (wpDetailEntity.getWdId().equals(detailEntity.getWdId())){
                        in = true;
                        break;
                    }
                }
                if (!in)
                    deleteArray.add(wpDetailEntity);
            }
        }
        return deleteArray;
    }

    /**
     * 建造明细数据
     * @param warehouseDetailVo
     * @throws NotFoundException
     */
    private List<WpDetailEntity> buildDetails(WarehouseDetailVo warehouseDetailVo,WarehouseEntity warehouseEntity,
                                             CustomerEntity customerEntity) throws NotFoundException {
        int id = warehouseDetailVo.getId().intValue();
        List<WpDetailEntity> outs = new ArrayList<>();
        if (warehouseDetailVo.getDatas()!=null){
            for (WpDetailEntity wpDetailEntity : warehouseDetailVo.getDatas()) {
                if ((!warehouseDetailVo.getType()&&wpDetailEntity.getOutNumber() <=0)||
                        (warehouseDetailVo.getType() && wpDetailEntity.getInNumber() <=0))
                    continue;
                WpDetailEntity w = detailDao.loadOne(warehouseDetailVo.getType()?1:0,id,
                        wpDetailEntity.getTbProductFormatByPfId().getPfId());
                if (w == null) {
                    w = addDetail(warehouseDetailVo, id, warehouseEntity, customerEntity, wpDetailEntity);
                }else {
                    modifyDetail(warehouseDetailVo, warehouseEntity, wpDetailEntity, w);
                }
                outs.add(w);
            }

        }
        return outs;
    }

    /**
     * 修改产品明细
     * @param warehouseDetailVo
     * @param warehouseEntity
     * @param wpDetailEntity
     * @param w
     */
    private void modifyDetail(WarehouseDetailVo warehouseDetailVo, WarehouseEntity warehouseEntity,
                              WpDetailEntity wpDetailEntity, WpDetailEntity w) {
        ProductFormatEntity formatEntity = w.getTbProductFormatByPfId();
        w.setTbWarehouseByWhId(warehouseEntity);
        w.setInNumber(wpDetailEntity.getInNumber());
        w.setOutNumber(wpDetailEntity.getOutNumber());
        w.setWdTotal(warehouseDetailVo.getType()?
                w.getWdPrice().multiply(BigDecimal.valueOf(wpDetailEntity.getInNumber())):
                w.getWdPrice().multiply(BigDecimal.valueOf(wpDetailEntity.getOutNumber())));
        w.setWdCost(warehouseDetailVo.getType()?
                w.getWdPrice().subtract(formatEntity.getPfCost()).multiply(BigDecimal.valueOf(wpDetailEntity.getInNumber())):
                w.getWdPrice().subtract(formatEntity.getPfCost()).multiply(BigDecimal.valueOf(wpDetailEntity.getOutNumber())));
        w.setWdOther(wpDetailEntity.getWdOther());
    }

    /**
     * 添加产品明细数据
     * @param warehouseDetailVo
     * @param id
     * @param warehouseEntity
     * @param customerEntity
     * @param wpDetailEntity
     * @throws NotFoundException
     */
    private WpDetailEntity addDetail(WarehouseDetailVo warehouseDetailVo, int id, WarehouseEntity warehouseEntity,
                           CustomerEntity customerEntity, WpDetailEntity wpDetailEntity)
            throws NotFoundException {
        ProductFormatEntity formatEntity = productService.load(wpDetailEntity.getTbProductFormatByPfId().getPfId());
        wpDetailEntity.setTbProductFormatByPfId(formatEntity);
        wpDetailEntity.setWpId(id);
        wpDetailEntity.setWdState(0);
        wpDetailEntity.setWdType(warehouseDetailVo.getType() ? 1 : 0);
        wpDetailEntity.setTbWarehouseByWhId(warehouseEntity);
        wpDetailEntity.setTbCustomerByCusId(customerEntity);
        wpDetailEntity.setWdPrice(formatEntity.getPfPrice());
        wpDetailEntity.setPlanNumber(0L);
        wpDetailEntity.setWdTotal(warehouseDetailVo.getType()?
                formatEntity.getPfPrice().multiply(BigDecimal.valueOf(wpDetailEntity.getInNumber())):
                formatEntity.getPfPrice().multiply(BigDecimal.valueOf(wpDetailEntity.getOutNumber())));
        wpDetailEntity.setWdCost(warehouseDetailVo.getType()?
                formatEntity.getPfPrice().subtract(formatEntity.getPfCost()).multiply(BigDecimal.valueOf(wpDetailEntity.getInNumber())):
                formatEntity.getPfPrice().subtract(formatEntity.getPfCost()).multiply(BigDecimal.valueOf(wpDetailEntity.getOutNumber())));
        return wpDetailEntity;
    }

    /**
     * 确认入库或者出库
     * @param vos
     */
    public void enter(WarehouseDetailVo vos,UserEntity userEntity) throws NotFoundException, ServiceException {
        if (!vos.getType())
            enterOut(vos,userEntity);
        else
            enterIn(vos,userEntity);
    }

    /**
     * 撤销出库或者入库
     * @param id
     */
    public void cancel(Long id, int type) throws NotFoundException, ServiceException {
        if (type == 0){
            cancelOut(id);
        }else if (type == 1)
            cancelIn(id);
    }

    /**
     * 撤销出库
     * @param id
     * @throws NotFoundException
     * @throws ServiceException
     */
    private void cancelOut(Long id) throws NotFoundException, ServiceException {
        WhPullEntity whPullEntity = wareHouseService.loadOut(id.intValue());
        if (whPullEntity.getWpullStatus() == 0)
            throw new ServiceException("该出库单未出库,不需要撤销");
        if (whPullEntity.getWpullStatus() == 2)
            throw new ServiceException("该出库单已经发货，无法撤销");
        if (whPullEntity.getTbReturnGoodsByRgId() != null)
            throw new ServiceException("退货单不允许撤销");
        if (whPullEntity.getTbOrderByOrderId() != null && whPullDao.haveReturn(whPullEntity.getTbOrderByOrderId())>0){
            throw new ServiceException("有退货单的采购单不允许撤销");
        }
        whPullEntity.setWpullStatus(0);
        whPullEntity.setWpullExecute(null);
        whPullEntity.setTbUserByTbUserId(null);
        List<DetailOutVo> outStorageVos = loadOutDetail(id);
        try {
            for (DetailOutVo outStorageVo : outStorageVos) {
                wareHouseService.modifyWareHouseNumber(outStorageVo.getProductId().intValue(), outStorageVo.getWhId(),
                        outStorageVo.getOutNumber());
            }
            warehouseSend.deleteSend(whPullEntity);
            detailDao.cancel(id,0);
            whPullDao.save(whPullEntity);
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("撤销出库失败");
        }
    }
    /**
     * 撤销入库
     * @param id
     * @throws NotFoundException
     * @throws ServiceException
     */
    private void cancelIn(Long id) throws NotFoundException, ServiceException {
        WhPutEntity whPutEntity = wareHouseService.loadIn(id.intValue());
        if (whPutEntity.getWpStatus() == 0)
            throw new ServiceException("该入库单未执行,不需要撤销");
        if (whPutEntity.getTbReturnGoodsByRgId() != null)
            throw new ServiceException("退货单不允许撤销");
        if (whPutEntity.getTbPurchaseByPurId() != null && inStorageDao.haveReturn(whPutEntity.getTbPurchaseByPurId())>0){
            throw new ServiceException("有退货单的采购单不允许撤销");
        }
        whPutEntity.setWpStatus(0);
        whPutEntity.setWpExecute(null);
        whPutEntity.setTbUserByTbUserId(null);
        List<DetailOutVo> outStorageVos = loadOutDetail(id);
        try {
            for (DetailOutVo outStorageVo : outStorageVos) {
                wareHouseService.modifyWareHouseNumber(outStorageVo.getProductId().intValue(), outStorageVo.getWhId(),
                        outStorageVo.getOutNumber()*(-1));
            }
            detailDao.cancel(id,1);
            inStorageDao.save(whPutEntity);
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("撤销入库失败");
        }
    }


    /**
     * 确认出库
     * @param vos
     * @throws NotFoundException
     * @throws ServiceException
     */
    private void enterOut(WarehouseDetailVo vos,UserEntity userEntity) throws NotFoundException, ServiceException {
        WhPullEntity whPullEntity = wareHouseService.loadOut(vos.getId().intValue());
        if (whPullEntity.getWpullStatus() != 0)
            throw new ServiceException("该出库单已经被执行");
        whPullEntity.setWpullExecute(Date.valueOf(LocalDate.now()));
        whPullEntity.setTbUserByTbUserId(null);
        whPullEntity.setWpullStatus(1);
        whPullEntity.setTbUserByTbUserId(userEntity);
        List<DetailOutVo> outStorageVos = loadOutDetail(vos.getId());
        if (outStorageVos == null || outStorageVos.size()<=0)
            throw new ServiceException("该出库单没有产品需要出库");
        for (DetailOutVo outStorageVo : outStorageVos)
            if (outStorageVo.getOutNumber() > outStorageVo.getWhNumber())
                throw new ServiceException("产品"+outStorageVo.getProductTitle()+"库存不足");
        try {
            for (DetailOutVo outStorageVo : outStorageVos) {
                wareHouseService.modifyWareHouseNumber(outStorageVo.getProductId().intValue(), outStorageVo.getWhId(),
                        outStorageVo.getOutNumber() * (-1));
            }
            if (whPullEntity.getTbOrderByOrderId() != null)
                warehouseSend.addSend(whPullEntity);
            detailDao.execute(vos.getId(),0);
            whPullDao.save(whPullEntity);
            if (whPullEntity.getTbOrderByOrderId() != null)
                orderService.rereshDetail(whPullEntity.getTbOrderByOrderId().getOrderId().longValue());
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("出库失败");
        }

    }

    /**
     * 确认入库
     * @param vos
     * @throws NotFoundException
     * @throws ServiceException
     */
    private void enterIn(WarehouseDetailVo vos,UserEntity userEntity) throws NotFoundException, ServiceException {
        WhPutEntity whPutEntity = wareHouseService.loadIn(vos.getId().intValue());
        if (whPutEntity.getWpStatus() != 0)
            throw new ServiceException("该入库单已经被执行");
        whPutEntity.setWpExecute(Date.valueOf(LocalDate.now()));
        whPutEntity.setTbUserByTbUserId(null);
        whPutEntity.setWpStatus(1);
        whPutEntity.setTbUserByTbUserId(userEntity);
        List<DetailOutVo> outStorageVos = loadInDetail(vos.getId());
        if (outStorageVos == null || outStorageVos.size()<=0)
            throw new ServiceException("该入库单没有产品需要出库");
        try {
            for (DetailOutVo outStorageVo : outStorageVos) {
                wareHouseService.modifyWareHouseNumber(outStorageVo.getProductId().intValue(), outStorageVo.getWhId(),
                        outStorageVo.getInNumber());
            }
            detailDao.execute(vos.getId(),1);
            inStorageDao.save(whPutEntity);
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("入库失败");
        }

    }

    /**
     * 加载出入库明细
     * @param i
     * @param pullId
     * @return
     */
    public List<WpDetailEntity> loadAllDetail(int i, Integer pullId) {
        return detailDao.loadAll(pullId,i);
    }

    /**
     * 订单生成出库单
     *
     * @param id
     * @return
     */
    public WhPullEntity orderOut(Long id, Long warehouseId) throws NotFoundException, ServiceException {
      OrderEntity orderEntity = orderService.load(id);
      if (!haveNoPull(id))
          throw new ServiceException("该订单有未执行的出库单");
      if (orderEntity.getOrderStatus() !=0)
          throw new ServiceException("订单已结束");
      if (orderEntity.getOrderOk() != 2)
          throw new ServiceException("订单未经过审核");
      WarehouseEntity warehouseEntity = wareHouseService.loadWareHouse(warehouseId);
      try {
          WhPullEntity w = whPullDao.save(WarehouseUtils.orderOut(orderEntity,null,warehouseEntity));
          wareHouseDetailDao.save(WarehouseUtils.buildWpDetail(orderEntity,w,orderService,null));
          return w;
      }catch (Exception e){
          e.printStackTrace();
          throw new ServiceException("添加出库单失败");
      }
    }
    /**
     * 采购单生成入库单
     *
     * @param id
     * @return
     */
    public WhPutEntity purchaseIn(Long id) throws NotFoundException, ServiceException {
        PurchaseEntity purchaseEntity = purchaseService.load(id.intValue());
        if (!haveNoPut(id))
            throw new ServiceException("该采购单有未执行的入库单");
        if (purchaseEntity.getPurOk() != 0 && purchaseEntity.getPurOk() != 3)
            throw new ServiceException("采购单未被审批");
        try {
            WhPutEntity w = inStorageDao.save(WarehouseUtils.purchaseIn(purchaseEntity,null));
            wareHouseDetailDao.save(WarehouseUtils.buildWputDetail(purchaseEntity,w,purchaseService,null));
            return w;
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("添加入库单失败");
        }
    }

    /**
     * 采购退货单生成出库单
     * @param id
     * @return
     * @throws NotFoundException
     * @throws ServiceException
     */
    public WhPullEntity returnOut(Integer id) throws NotFoundException, ServiceException {
        ReturnGoodsEntity returnGoodsEntity = returnGoodsService.load(id);
        if (returnGoodsEntity.getRgType()!=0)
            throw new ServiceException("采购退货单信息不正确");
        if (!haveNoPull(id))
            throw new ServiceException("该采购退货单有未执行的出库单");
        try {
            returnGoodsEntity.setRgState("正在处理");
            returnGoodsDao.save(returnGoodsEntity);
            WhPullEntity w = whPullDao.save(WarehouseUtils.returnOut(returnGoodsEntity,null));
            wareHouseDetailDao.save(WarehouseUtils.buildWpDetail(returnGoodsEntity,w,null));
            return w;
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("添加出库单失败");
        }

    }

    /**
     * 订单退货单生成入库单
     * @param id
     * @return
     * @throws NotFoundException
     * @throws ServiceException
     */
    public WhPutEntity returnIn(Integer id) throws NotFoundException, ServiceException {
        ReturnGoodsEntity returnGoodsEntity = returnGoodsService.load(id);
        if (returnGoodsEntity.getRgType()!=1)
            throw new ServiceException("订单退货单信息不正确");
        //判断是否有未执行的退货单
        if (!haveNoPull(id))
            throw new ServiceException("该订单退货单有未执行的入库单");
        try {
            returnGoodsEntity.setRgState("正在处理");
            returnGoodsDao.save(returnGoodsEntity);
            WhPutEntity w = inStorageDao.save(WarehouseUtils.returnIn(returnGoodsEntity,null));
            wareHouseDetailDao.save(WarehouseUtils.buildWpDetail(returnGoodsEntity,w,null));
            return w;
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("添加入库单失败");
        }

    }

    /**
     * 订单生成出库单加载选择仓库信息
     * @param id
     * @return
     */
    public List<ChooseWarehouseVo> chooseWarehouse(Long id){
        return outStorageMapper.loadProductOut(id);
    }

    /**
     * 判断订单有无未出库的出库单
     * @param id
     * @return
     */
    public boolean haveNoPull(Long id) throws NotFoundException {
        Integer count = whPullDao.sumNoPull(false,id.intValue());
        if (count > 0)
            return false;
        return true;
    }
    /**
     * 判断有无未入库的入库单
     * @param id
     * @return
     */
    public boolean haveNoPut(Long id) throws NotFoundException {
        Integer count = inStorageDao.sumNoPut(false,id.intValue());
        if (count > 0)
            return false;
        return true;
    }
    /**
     * 判断采购退货单有无未出库的出库单
     * @param id
     * @return
     */
    public boolean haveNoPull(Integer id) throws NotFoundException {
        Integer count = whPullDao.sumNoPullReturn(false,id);
        if (count > 0)
            return false;
        return true;
    }
    /**
     * 判断订单退货单有无未入库的入库单
     * @param id
     * @return
     */
    public boolean haveNoPut(Integer id) throws NotFoundException {
        Integer count = inStorageDao.sumNoPutReturn(false,id);
        if (count > 0)
            return false;
        return true;
    }

    /**
     * 判断有无产品需要交付
     * @param id
     * @return
     */
    public boolean canOut(Long id) {
        List<OrderDetail> orderDetails = orderService.loadDeatil(id);
        for (OrderDetail orderDetail : orderDetails) {
            if (orderDetail.getNoPay() > 0)
                return true;
        }
        return false;
    }
}
